#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "ohos_init.h"

#include <dtls_al.h>
#include <mqtt_al.h>
#include <oc_mqtt_al.h>
#include <oc_mqtt_profile.h>
#include "E53_IA1.h"
#include "wifi_sta_connect.h"

#define CONFIG_WIFI_SSID "OnePlus7Pro" // 修改为自己的WiFi 热点账号

#define CONFIG_WIFI_PWD "3070806544" // 修改为自己的WiFi 热点密码





#define CONFIG_APP_SERVERIP "97d51a16de.iot-mqtts.cn-north-4.myhuaweicloud.com"

#define CONFIG_APP_SERVERPORT "1883"

#define CONFIG_APP_DEVICEID "62c6cb234c7c4e3646b98f2b_12345678abcdefg" // 替换为注册设备后生成的deviceid

#define CONFIG_APP_DEVICEPWD "1fb864d236530aaf49f2596dc4deaac4" // 替换为注册设备后生成的密钥







#define CONFIG_APP_LIFETIME 60 // seconds

#define CONFIG_QUEUE_TIMEOUT (5 * 1000)


#define MSGQUEUE_COUNT 16
#define MSGQUEUE_SIZE 10
#define CLOUD_TASK_STACK_SIZE (1024 * 10)
#define CLOUD_TASK_PRIO 24
#define SENSOR_TASK_STACK_SIZE (1024 * 4)
#define SENSOR_TASK_PRIO 25
#define TASK_DELAY 3
osMessageQueueId_t mid_MsgQueue; // message queue id
typedef enum {
    en_msg_cmd = 0,
    en_msg_report,
    en_msg_conn,
    en_msg_disconn,
} en_msg_type_t;

typedef struct {
    char* request_id;
    char* payload;
} cmd_t;

typedef struct {
    int lum;
    int temp;
    int hum;
} report_t;

typedef struct {
    en_msg_type_t msg_type;
    union {
        cmd_t cmd;
        report_t report;
    } msg;
} app_msg_t;

typedef struct {
    osMessageQueueId_t app_msg;
    int connected;
    int led;
    int motor;
} app_cb_t;
static app_cb_t g_app_cb;

static void deal_report_msg(report_t* report)
{
    oc_mqtt_profile_service_t service;
    oc_mqtt_profile_kv_t temperature;
    oc_mqtt_profile_kv_t humidity;
    oc_mqtt_profile_kv_t led;
    oc_mqtt_profile_kv_t motor;

    if (g_app_cb.connected != 1) {
        return;
    }

    service.event_time = NULL;
    service.service_id = "Agriculture";
    service.service_property = &temperature;
    service.nxt = NULL;

    temperature.key = "Temperature";
    temperature.value = &report->temp;
    temperature.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    temperature.nxt = &humidity;

    humidity.key = "Humidity";
    humidity.value = &report->hum;
    humidity.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    humidity.nxt = &led;


    led.key = "LightStatus";
    led.value = g_app_cb.led ? "ON" : "OFF";
    led.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    led.nxt = &motor;

    motor.key = "MotorStatus";
    motor.value = g_app_cb.motor ? "ON" : "OFF";
    motor.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    motor.nxt = NULL;

    oc_mqtt_profile_propertyreport(CONFIG_APP_DEVICEID, &service);
    return;
}

// use this function to push all the message to the buffer
static int msg_rcv_callback(oc_mqtt_profile_msgrcv_t* msg)
{
    int ret = 0;
    char* buf;
    int buf_len;
    app_msg_t* app_msg;

    if ((msg == NULL) || (msg->request_id == NULL) || (msg->type != EN_OC_MQTT_PROFILE_MSG_TYPE_DOWN_COMMANDS)) {
        return ret;
    }

    buf_len = sizeof(app_msg_t) + strlen(msg->request_id) + 1 + msg->msg_len + 1;
    buf = malloc(buf_len);
    if (buf == NULL) {
        return ret;
    }
    app_msg = (app_msg_t*)buf;
    buf += sizeof(app_msg_t);

    app_msg->msg_type = en_msg_cmd;
    app_msg->msg.cmd.request_id = buf;
    buf_len = strlen(msg->request_id);
    buf += buf_len + 1;
    memcpy_s(app_msg->msg.cmd.request_id, buf_len, msg->request_id, buf_len);
    app_msg->msg.cmd.request_id[buf_len] = '\0';

    buf_len = msg->msg_len;
    app_msg->msg.cmd.payload = buf;
    memcpy_s(app_msg->msg.cmd.payload, buf_len, msg->msg, buf_len);
    app_msg->msg.cmd.payload[buf_len] = '\0';

    ret = osMessageQueuePut(g_app_cb.app_msg, &app_msg, 0U, CONFIG_QUEUE_TIMEOUT);
    if (ret != 0) {
        free(app_msg);
    }

    return ret;
}

static void oc_cmdresp(cmd_t* cmd, int cmdret)
{
    oc_mqtt_profile_cmdresp_t cmdresp;
    ///< do the response
    cmdresp.paras = NULL;
    cmdresp.request_id = cmd->request_id;
    cmdresp.ret_code = cmdret;
    cmdresp.ret_name = NULL;
    (void)oc_mqtt_profile_cmdresp(NULL, &cmdresp);
}

///< COMMAND DEAL
#include <cJSON.h>
static void deal_light_cmd(cmd_t* cmd, cJSON* obj_root)
{
    cJSON* obj_paras;
    cJSON* obj_para;
    int cmdret;

    obj_paras = cJSON_GetObjectItem(obj_root, "paras");
    if (NULL == obj_paras) {
        cJSON_Delete(obj_root);
    }
    obj_para = cJSON_GetObjectItem(obj_paras, "Light");
    if (NULL == obj_paras) {
        cJSON_Delete(obj_root);
    }
    ///< operate the LED here
    printf("value: %s \r\n", cJSON_GetStringValue(obj_para));
    if (strcmp(cJSON_GetStringValue(obj_para), "ON") == 0) {
        g_app_cb.led = 1;
        Light_StatusSet(ON);
        printf("Light On!\r\n");
    } else {
        g_app_cb.led = 0;
        Light_StatusSet(OFF);
        printf("Light Off!\r\n");
    }
    cmdret = 0;
    oc_cmdresp(cmd, cmdret);

_ERR:
    cJSON_Delete(obj_root);
    return;
}

static void deal_motor_cmd(cmd_t* cmd, cJSON* obj_root)
{
    cJSON* obj_paras;
    cJSON* obj_para;
    int cmdret;

    obj_paras = cJSON_GetObjectItem(obj_root, "Paras");
    if (NULL == obj_paras) {
        cJSON_Delete(obj_root);
    }
    obj_para = cJSON_GetObjectItem(obj_paras, "Motor");
    if (NULL == obj_para) {
        cJSON_Delete(obj_root);
    }
    ///< operate the Motor here
    if (strcmp(cJSON_GetStringValue(obj_para), "ON") == 0) {
        g_app_cb.motor = 1;
        Motor_StatusSet(ON);
        printf("Motor On!\r\n");
    } else {
        g_app_cb.motor = 0;
        Motor_StatusSet(OFF);
        printf("Motor Off!\r\n");
    }
    cmdret = 0;
    oc_cmdresp(cmd, cmdret);

_ERR:
    cJSON_Delete(obj_root);
    return;
}

static void deal_cmd_msg(cmd_t* cmd)
{
    cJSON* obj_root;
    cJSON* obj_cmdname;

    int cmdret = 1;
    printf("cmd->payload %s \r\n",cmd->payload);
    obj_root = cJSON_Parse(cmd->payload);
    if (NULL == obj_root) {
        oc_cmdresp(cmd, cmdret);
    }
    obj_cmdname = cJSON_GetObjectItem(obj_root, "command_name");
    if (NULL == obj_cmdname) {
        cJSON_Delete(obj_root);
    }
    if (strcmp(cJSON_GetStringValue(obj_cmdname), "Agriculture_Control_Light") == 0) {
        deal_light_cmd(cmd, obj_root);
    } else if (strcmp(cJSON_GetStringValue(obj_cmdname), "Agriculture_Control_Motor") == 0) {
        deal_motor_cmd(cmd, obj_root);
    }

    return;
}




// #define CONFIG_APP_SERVERIP "a1618b7ff0.iot-mqtts.cn-north-4.myhuaweicloud.com"

// #define CONFIG_APP_SERVERPORT "1883"

// #define CONFIG_APP_DEVICEID "62aaf343906b9e29ac76424c_b84d4335a835" // 替换为注册设备后生成的deviceid

// #define CONFIG_APP_DEVICEPWD "485a9d7a5617a333987925a62f4caf84ee11863bb1bba03e7d13c7d9850852cf" // 替换为注册设备后生成的密钥

// #define CONFIG_APP_LIFETIME 60 // seconds

// #define CONFIG_QUEUE_TIMEOUT (5 * 1000)

// #define MSGQUEUE_COUNT 16
// #define MSGQUEUE_SIZE 10
// #define CLOUD_TASK_STACK_SIZE (1024 * 10)
// #define CLOUD_TASK_PRIO 24
// #define SENSOR_TASK_STACK_SIZE (1024 * 4)
// #define SENSOR_TASK_PRIO 25
// #define TASK_DELAY 3
static int task_main_entry(void)
{

    //连接wifi
    app_msg_t* app_msg;
    uint32_t ret;

    WifiConnect(CONFIG_WIFI_SSID, CONFIG_WIFI_PWD);
    dtls_al_init();
    mqtt_al_init();
    oc_mqtt_init();

    g_app_cb.app_msg = osMessageQueueNew(MSGQUEUE_COUNT, MSGQUEUE_SIZE, NULL);
    if (g_app_cb.app_msg == NULL) {
        printf("Create receive msg queue failed");
    }


    //连接mqtt
    oc_mqtt_profile_connect_t connect_para;
    (void)memset_s(&connect_para, sizeof(connect_para), 0, sizeof(connect_para));

    connect_para.boostrap = 0;
    connect_para.device_id = CONFIG_APP_DEVICEID;
    connect_para.device_passwd = CONFIG_APP_DEVICEPWD;
    connect_para.server_addr = CONFIG_APP_SERVERIP;
    connect_para.server_port = CONFIG_APP_SERVERPORT;
    connect_para.life_time = CONFIG_APP_LIFETIME;
    connect_para.rcvfunc = msg_rcv_callback;
    connect_para.security.type = EN_DTLS_AL_SECURITY_TYPE_NONE;
    ret = oc_mqtt_profile_connect(&connect_para);
    if ((ret == (int)en_oc_mqtt_err_ok)) {
        g_app_cb.connected = 1;
        printf("oc_mqtt_profile_connect succed!\r\n");
    } else {
        printf("oc_mqtt_profile_connect faild!\r\n");
    }


   //死循环mqtt命令判断
    while (1) {
        app_msg = NULL;
        (void)osMessageQueueGet(g_app_cb.app_msg, (void**)&app_msg, NULL, 0xFFFFFFFF);
        if (app_msg != NULL) {
            switch (app_msg->msg_type) {
                case en_msg_cmd:
                    deal_cmd_msg(&app_msg->msg.cmd);
                    break;
                case en_msg_report:
                    deal_report_msg(&app_msg->msg.report);
                    break;
                default:
                    break;
            }
            free(app_msg);
        }
    }
    return 0;
}

static int task_sensor_entry(void)
{
    app_msg_t* app_msg;
    int ret;
    E53_IA1_Data_TypeDef data;

    E53_IA1_Init();
    while (1) {
        E53_IA1_Read_Data(&data);
        hi_watchdog_feed();
        app_msg = malloc(sizeof(app_msg_t));
        printf("SENSOR:temp:%.2f hum:%.2f\r\n", data.Temperature, data.Humidity);
        if (NULL != app_msg) {
            app_msg->msg_type = en_msg_report;
            app_msg->msg.report.hum = (int)data.Humidity;
            app_msg->msg.report.temp = (int)data.Temperature;
            if (osMessageQueuePut(g_app_cb.app_msg, &app_msg, 0U, CONFIG_QUEUE_TIMEOUT != 0)) {
                free(app_msg);
            }
        }
        printf("data en queue\r\n");
        sleep(TASK_DELAY);
    }
    return 0;
}

static void IotMainTaskEntry(void)
{
    osThreadAttr_t attr;

    attr.name = "task_main_entry";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = CLOUD_TASK_STACK_SIZE;
    attr.priority = CLOUD_TASK_PRIO;

    if (osThreadNew((osThreadFunc_t)task_main_entry, NULL, &attr) == NULL) {
        printf("Failed to create task_main_entry!\n");
    }
    attr.stack_size = SENSOR_TASK_STACK_SIZE;
    attr.priority = SENSOR_TASK_PRIO;
    attr.name = "task_sensor_entry";
    if (osThreadNew((osThreadFunc_t)task_sensor_entry, NULL, &attr) == NULL) {
        printf("Failed to create task_sensor_entry!\n");
    }
}

APP_FEATURE_INIT(IotMainTaskEntry);